<!DOCTYPE html>
<html lang="zh-CN">
    <!-- title -->


    

<!-- keywords -->



<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="author" content="Lolipop">
    <meta name="renderer" content="webkit">
    <meta name="copyright" content="Lolipop">
    
        <meta name="keywords" content="Lolipop,frontend,full-stack,前端,全栈">
    
    <meta name="description" content="">
    <meta name="description" content="最近学习前端基础知识的时候，看到了这个问题和一个回答，非常生动有趣。遂抱着梳理的想法，将整个过程描述出来。 现在，假设您打开了浏览器，想要访问我的个人博客，您会在地址栏输入 lolipopj.github.io 这个 URL 然后敲下回车键。 从敲下回车键到最终顺利在浏览器显示我博客的主页，这个过程的背后发生了什么呢？ 检查 URL 格式别急，在正式驶入互联网的快车道之前，浏览器会首先检查输入的">
<meta property="og:type" content="article">
<meta property="og:title" content="在浏览器中输入 URL 到显示网页，背后发生了什么">
<meta property="og:url" content="https://lolipopj.github.io/2021/07/07/browser-behind-visit-url/index.html">
<meta property="og:site_name" content="Lolipop">
<meta property="og:description" content="最近学习前端基础知识的时候，看到了这个问题和一个回答，非常生动有趣。遂抱着梳理的想法，将整个过程描述出来。 现在，假设您打开了浏览器，想要访问我的个人博客，您会在地址栏输入 lolipopj.github.io 这个 URL 然后敲下回车键。 从敲下回车键到最终顺利在浏览器显示我博客的主页，这个过程的背后发生了什么呢？ 检查 URL 格式别急，在正式驶入互联网的快车道之前，浏览器会首先检查输入的">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2021-07-07T16:00:00.000Z">
<meta property="article:modified_time" content="2021-07-22T16:00:00.000Z">
<meta property="article:author" content="Lolipop">
<meta property="article:tag" content="计算机网络">
<meta property="article:tag" content="网络安全">
<meta property="article:tag" content="密码学">
<meta name="twitter:card" content="summary">
    <meta http-equiv="Cache-control" content="no-cache">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <link rel="icon" href="https://cdn.jsdelivr.net/gh/lolipopj/LolipopJ.github.io/static/assets/favicon.ico">
    
    <title>在浏览器中输入 URL 到显示网页，背后发生了什么 · Lolipop&#39;s Studio</title>
    <!-- /*! loadCSS. [c]2017 Filament Group, Inc. MIT License */
/* This file is meant as a standalone workflow for
- testing support for link[rel=preload]
- enabling async CSS loading in browsers that do not support rel=preload
- applying rel preload css once loaded, whether supported or not.
*/ -->
<script>
    (function (w) {
        'use strict'
        // rel=preload support test
        if (!w.loadCSS) {
            w.loadCSS = function () {}
        }
        // define on the loadCSS obj
        var rp = (loadCSS.relpreload = {})
        // rel=preload feature support test
        // runs once and returns a function for compat purposes
        rp.support = (function () {
            var ret
            try {
                ret = w.document.createElement('link').relList.supports('preload')
            } catch (e) {
                ret = false
            }
            return function () {
                return ret
            }
        })()

        // if preload isn't supported, get an asynchronous load by using a non-matching media attribute
        // then change that media back to its intended value on load
        rp.bindMediaToggle = function (link) {
            // remember existing media attr for ultimate state, or default to 'all'
            var finalMedia = link.media || 'all'

            function enableStylesheet() {
                link.media = finalMedia
            }

            // bind load handlers to enable media
            if (link.addEventListener) {
                link.addEventListener('load', enableStylesheet)
            } else if (link.attachEvent) {
                link.attachEvent('onload', enableStylesheet)
            }

            // Set rel and non-applicable media type to start an async request
            // note: timeout allows this to happen async to let rendering continue in IE
            setTimeout(function () {
                link.rel = 'stylesheet'
                link.media = 'only x'
            })
            // also enable media after 3 seconds,
            // which will catch very old browsers (android 2.x, old firefox) that don't support onload on link
            setTimeout(enableStylesheet, 3000)
        }

        // loop through link elements in DOM
        rp.poly = function () {
            // double check this to prevent external calls from running
            if (rp.support()) {
                return
            }
            var links = w.document.getElementsByTagName('link')
            for (var i = 0; i < links.length; i++) {
                var link = links[i]
                // qualify links to those with rel=preload and as=style attrs
                if (
                    link.rel === 'preload' &&
                    link.getAttribute('as') === 'style' &&
                    !link.getAttribute('data-loadcss')
                ) {
                    // prevent rerunning on link
                    link.setAttribute('data-loadcss', true)
                    // bind listeners to toggle media back
                    rp.bindMediaToggle(link)
                }
            }
        }

        // if unsupported, run the polyfill
        if (!rp.support()) {
            // run once at least
            rp.poly()

            // rerun poly on an interval until onload
            var run = w.setInterval(rp.poly, 500)
            if (w.addEventListener) {
                w.addEventListener('load', function () {
                    rp.poly()
                    w.clearInterval(run)
                })
            } else if (w.attachEvent) {
                w.attachEvent('onload', function () {
                    rp.poly()
                    w.clearInterval(run)
                })
            }
        }

        // commonjs
        if (typeof exports !== 'undefined') {
            exports.loadCSS = loadCSS
        } else {
            w.loadCSS = loadCSS
        }
    })(typeof global !== 'undefined' ? global : this)
</script>

    <style type="text/css">
    @font-face {
        font-family: 'Oswald-Regular';
        src: url("/font/Oswald-Regular.ttf");
    }

    body {
        margin: 0;
    }

    header,
    footer,
    .back-top,
    .sidebar,
    .container,
    .site-intro-meta,
    .toc-wrapper {
        display: none;
    }

    .site-intro {
        position: relative;
        z-index: 3;
        width: 100%;
        /* height: 50vh; */
        overflow: hidden;
    }

    .site-intro-placeholder {
        position: absolute;
        z-index: -2;
        top: 0;
        left: 0;
        width: calc(100% + 300px);
        height: 100%;
        background: repeating-linear-gradient(-45deg, #444 0, #444 80px, #333 80px, #333 160px);
        background-position: center center;
        transform: translate3d(-226px, 0, 0);
        animation: gradient-move 2.5s ease-out 0s infinite;
    }

    @keyframes gradient-move {
        0% {
            transform: translate3d(-226px, 0, 0);
        }
        100% {
            transform: translate3d(0, 0, 0);
        }
    }
</style>

    <link rel="preload" href="/css/style.css?v=20211217" as="style" onload="this.onload=null;this.rel='stylesheet'">
    <link rel="preload" href="/css/dark.css?v=20211217" as="style">
    <link rel="stylesheet" href="/css/dark.css">
    <link rel="stylesheet" href="/css/mobile.css?v=20211217" media="(max-width: 960px)">
    <link rel="preload" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
    <link rel="preload" href="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js" as="script">
    <link rel="preload" href="/scripts/main.js?v=20211217" as="script">
    <link rel="preload" href="/scripts/dark.js?v=20211217" as="script">
    <link rel="preload" href="/font/Oswald-Regular.ttf" as="font" crossorigin>
    <link rel="preload" href="https://at.alicdn.com/t/font_327081_1dta1rlogw17zaor.woff" as="font" crossorigin>
    <!-- algolia -->
    
        <script>
            var hits = JSON.parse('{"per_page":10}')
            var labels = JSON.parse('{"input_placeholder":"搜索博客","hits_empty":"Ops，我未能提供任何搜索结果：${query}","hits_stats":"在 ${time} ms 内找到了 ${hits} 个结果"}')

            var algolia = {
                applicationID: 'V9YD7AWBOS',
                apiKey: '5cb206cb0658a9daff865eef79de4bc4',
                indexName: 'lolipopJ.github.io',
                hits: hits,
                labels: labels
            }
        </script>
    
    <!-- 百度统计  -->
    
    <!-- 谷歌统计  -->
    
<meta name="generator" content="Hexo 5.4.1"><link rel="alternate" href="/atom.xml" title="Lolipop" type="application/atom+xml">
</head>

    <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
    <script type="text/javascript">
        if (typeof window.$ == undefined) {
            console.warn('jquery load from jsdelivr failed, will load local script')
            document.write('<script src="/lib/jquery.min.js" />')
        }
    </script>
    
        <body class="post-body">
    
        <!-- header -->
        <header class="header header-mobile">
    <!-- top read progress line -->
    <div class="header-element">
        <div class="read-progress read-progress-feature"></div>
    </div>
    <!-- sidebar menu button -->
    <div class="header-element">
        
            <div class="header-sidebar-menu header-sidebar-menu-rounded">
        
            
                <i class="fas fa-bars"></i>
            
        </div>
    </div>
    <!-- header actions -->
    <div class="header-actions">
        <!-- theme mode switch button -->
        <span class="header-theme-btn header-element">
            <i class="fas fa-adjust"></i>
        </span>
        <!-- back to home page text -->
        <span class="home-link header-element">
            <a href=/>Lolipop's Studio.</a>
        </span>
    </div>
    <!-- toggle banner for post layout -->
    
        
            <div class="banner banner-clean">
        
            <div class="blog-title header-element">
                <a href="/">Lolipop&#39;s Studio.</a>
            </div>
            <div class="post-title header-element">
                <a href="#" class="post-name">在浏览器中输入 URL 到显示网页，背后发生了什么</a>
            </div>
        </div>
    
</header>

        <!-- fixed footer -->
        <footer class="footer-fixed">
    <!-- back to top button -->
    <div class="footer-fixed-element">
        
            <div class="back-top back-top-hidden back-top-rounded">
        
        
            <i class="fas fa-chevron-up"></i>
        
        </div>
    </div>
</footer>

        <!-- wrapper -->
        <div class="wrapper">
            <div class="site-intro" style="







    height:50vh;

">
    
    <!-- 主页  -->
    
        
    <!-- 404页  -->
            
    <div class="site-intro-placeholder"></div>
    <div class="site-intro-img" style="background-image: url(https://source.unsplash.com/1600x900/?coder)"></div>
    <div class="site-intro-meta">
        <!-- 标题  -->
        <h1 class="intro-title">
            <!-- 主页  -->
            
                在浏览器中输入 URL 到显示网页，背后发生了什么
            <!-- 404 -->
            
        </h1>
        <!-- 副标题 -->
        <p class="intro-subtitle">
            <!-- 主页副标题  -->
            
                
            <!-- 404 -->
            
        </p>
        <!-- 文章页 meta -->
        
            <div class="post-intros">
                <!-- 文章页标签  -->
                
                    <div class= post-intro-tags >
    
        
        
            
        
        
        <span class="post-category" data-categories="学习琐事"">
            <i class="fas fa-folder post-category-icon"></i>
            <span class="post-category-text">
                学习琐事
            </span>
        </span>
    
    
        <a class="post-tag" href="javascript:void(0);" data-tags="计算机网络">计算机网络</a>
    
        <a class="post-tag" href="javascript:void(0);" data-tags="网络安全">网络安全</a>
    
        <a class="post-tag" href="javascript:void(0);" data-tags="密码学">密码学</a>
    
</div>

                
                
                    <div class="post-intro-read">
                        <span>字数统计: <span class="post-count word-count">8.8k</span>阅读时长: <span class="post-count reading-time">32 min</span></span>
                    </div>
                
                <div class="post-intro-meta">
                    <!-- 撰写日期 -->
                    <span class="iconfont-archer post-intro-calander">&#xe676;</span>
                    <span class="post-intro-time">2021/07/08</span>
                    <!-- busuanzi -->
                    
                        <span id="busuanzi_container_page_pv" class="busuanzi-pv">
                            <span class="iconfont-archer post-intro-busuanzi">&#xe602;</span>
                            <span id="busuanzi_value_page_pv"></span>
                        </span>
                    
                    <!-- 文章分享 -->
                    <span class="share-wrapper">
                        <span class="iconfont-archer share-icon">&#xe71d;</span>
                        <span class="share-text">Share</span>
                        <ul class="share-list">
                            <li class="iconfont-archer share-qr" data-type="qr">&#xe75b;
                                <div class="share-qrcode"></div>
                            </li>
                            <li class="iconfont-archer" data-type="weibo">&#xe619;</li>
                            <li class="iconfont-archer" data-type="qzone">&#xe62e;</li>
                            <li class="iconfont-archer" data-type="twitter">&#xe634;</li>
                            <li class="iconfont-archer" data-type="facebook">&#xe67a;</li>
                        </ul>
                    </span>
                </div>
            </div>
        
    </div>
</div>

            <script>
  // get user agent
  function getBrowserVersions() {
    var u = window.navigator.userAgent
    return {
      userAgent: u,
      trident: u.indexOf('Trident') > -1, //IE内核
      presto: u.indexOf('Presto') > -1, //opera内核
      webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
      gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
      mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否为移动终端
      ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
      android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或者uc浏览器
      iPhone: u.indexOf('iPhone') > -1 || u.indexOf('Mac') > -1, //是否为iPhone或者安卓QQ浏览器
      iPad: u.indexOf('iPad') > -1, //是否为iPad
      webApp: u.indexOf('Safari') == -1, //是否为web应用程序，没有头部与底部
      weixin: u.indexOf('MicroMessenger') == -1, //是否为微信浏览器
      uc: u.indexOf('UCBrowser') > -1, //是否为android下的UC浏览器
    }
  }
  var browser = {
    versions: getBrowserVersions(),
  }
  console.log('userAgent: ' + browser.versions.userAgent)

  // callback
  function fontLoaded() {
    console.log('font loaded')
    if (document.getElementsByClassName('site-intro-meta')) {
      document
        .getElementsByClassName('intro-title')[0]
        .classList.add('intro-fade-in')
      document
        .getElementsByClassName('intro-subtitle')[0]
        .classList.add('intro-fade-in')
      var postIntros = document.getElementsByClassName('post-intros')[0]
      if (postIntros) {
        postIntros.classList.add('post-fade-in')
      }
    }
  }

  // UC不支持跨域，所以直接显示
  function asyncCb() {
    if (browser.versions.uc) {
      console.log('UCBrowser')
      fontLoaded()
    } else {
      WebFont.load({
        custom: {
          families: ['Oswald-Regular'],
        },
        loading: function () {
          // 所有字体开始加载
          // console.log('font loading');
        },
        active: function () {
          // 所有字体已渲染
          fontLoaded()
        },
        inactive: function () {
          // 字体预加载失败，无效字体或浏览器不支持加载
          console.log('inactive: timeout')
          fontLoaded()
        },
        timeout: 5000, // Set the timeout to two seconds
      })
    }
  }

  function asyncErr() {
    console.warn('script load from CDN failed, will load local script')
  }

  // load webfont-loader async, and add callback function
  function async(u, cb, err) {
    var d = document,
      t = 'script',
      o = d.createElement(t),
      s = d.getElementsByTagName(t)[0]
    o.src = u
    if (cb) {
      o.addEventListener(
        'load',
        function (e) {
          cb(null, e)
        },
        false
      )
    }
    if (err) {
      o.addEventListener(
        'error',
        function (e) {
          err(null, e)
        },
        false
      )
    }
    s.parentNode.insertBefore(o, s)
  }

  var asyncLoadWithFallBack = function (arr, success, reject) {
    var currReject = function () {
      reject()
      arr.shift()
      if (arr.length) async(arr[0], success, currReject)
    }

    async(arr[0], success, currReject)
  }

  asyncLoadWithFallBack(
    [
      'https://cdn.jsdelivr.net/npm/webfontloader@1.6.28/webfontloader.min.js',
      'https://cdn.bootcss.com/webfont/1.6.28/webfontloader.js',
      "/lib/webfontloader.min.js",
    ],
    asyncCb,
    asyncErr
  )
</script>

            <img class="loading" src="/assets/loading.svg" style="display: block; margin: 6rem auto 0 auto; width: 6rem; height: 6rem;" />
            <div class="container container-unloaded">
                <main class="main post-page">
    <article class="article-entry">
        <p>最近学习前端基础知识的时候，看到了这个问题和<a target="_blank" rel="noopener" href="https://www.zhihu.com/question/34873227/answer/518086565">一个回答</a>，非常生动有趣。遂抱着梳理的想法，将整个过程描述出来。</p>
<p>现在，假设您打开了浏览器，想要访问我的个人博客，您会在地址栏输入 <code>lolipopj.github.io</code> 这个 URL 然后敲下回车键。</p>
<p>从敲下回车键到最终顺利在浏览器显示我博客的主页，这个过程的背后发生了什么呢？</p>
<h2 id="检查-URL-格式"><a href="#检查-URL-格式" class="headerlink" title="检查 URL 格式"></a>检查 URL 格式</h2><p>别急，在正式驶入互联网的快车道之前，浏览器会首先检查输入的 URL 的格式是否正确。</p>
<p>例如，假如您输入的是 <code>lolipop j.github.io</code>，或是 <code>lolipopj.gith$ub.io</code>，浏览器将会判断它们为非 URL。在这种情况下，浏览器通常会将我们错误输入的 URL 作为搜索引擎的输入关键字，最终跳转到搜索结果界面。</p>
<h3 id="什么是-URL"><a href="#什么是-URL" class="headerlink" title="什么是 URL"></a>什么是 URL</h3><ul>
<li><a target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/Identifying_resources_on_the_Web">「标识互联网上的内容」</a>，MDN</li>
</ul>
<p>HTTP 请求的内容非常宽泛，统称为“资源”。“资源”可以是一份文档，一张图片，或所有您可以想象到的格式。而这样的每个“资源”，都由一个<strong>统一资源定位符 URL</strong> 标识。</p>
<p>通俗地讲，URL 可以叫作“网络地址”或“链接”，它是对指定计算机网络上某位置的<strong>网络资源</strong>的引用，以及检索它的机制。一个典型的 URL 可以采用 <code>http://www.example.com/index.html</code> 形式表示，它表明了使用的协议（http），访问的主机名（<a target="_blank" rel="noopener" href="http://www.example.com)以及文件名(index.html)./">www.example.com）以及文件名（index.html）。</a></p>
<p>此外，URL 也可以用于文件传输（FTP），发送邮件（SMTP）和数据库访问（JDBC）等。</p>
<p>URL 是<strong>统一资源标志符 URI</strong> 的子集，由于早期 RFC 文档撰写的<a target="_blank" rel="noopener" href="https://danielmiessler.com/study/difference-between-uri-url/">一些混乱</a>，在实际使用中可能会发生混用的情况。在以 HTTP 为上下文的语境中，大多数情况使用 URL 即可。</p>
<h3 id="URL-格式"><a href="#URL-格式" class="headerlink" title="URL 格式"></a>URL 格式</h3><ul>
<li><a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/URL">「URL」</a>，Wikipedia</li>
</ul>
<p>URL 符合通用 URI 语法，格式如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">URI = scheme:[//authority]path[?query][#fragment]</span><br></pre></td></tr></table></figure>

<p>其中，<code>authority</code> 部分可以划分为三个子模块：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">authority = [userinfo@]host[:port]</span><br></pre></td></tr></table></figure>

<p>URI 具体包括如下部分：</p>
<ul>
<li><strong>非空的</strong> <code>scheme</code> 标识，后面跟着一个 <code>:</code>。由字母开头，后跟字母、数字、<code>+</code>、<code>.</code> 或连字符 <code>-</code> 的任意组合，规范建议使用小写格式。常见的例子有 <code>http:</code>，<code>https:</code> 和 <code>ftp:</code> 等。</li>
<li>可选的以 <code>//</code> 开头的 <code>authority</code> 权限组件，包括：<ul>
<li>可选的 <code>userinfo</code> 用户信息，可能包括用户名和用户密码，两者使用 <code>:</code> 分开。在后面跟着 <code>@</code>。出于安全考虑，应用程序不应当将用户密码部分用明文表示。</li>
<li><strong>非空的</strong> <code>host</code> 主机，由注册名称（例如主机名）或 IP 地址组成。对于后者，如果是 IPv4 地址，需要使用十进制表示法；如果是 IPv6 地址，需要包括在方括号 <code>[]</code> 中。</li>
<li>可选的以 <code>:</code> 开头的 <code>port</code> 端口号。</li>
</ul>
</li>
<li><strong>非空的</strong> <code>path</code> 路径，由一系列 <code>/</code> 分隔的路径段组成。路径将类似或完全映射到文件系统中。此外，如果存在 <code>authority</code> 权限组件，则必须为空或以 <code>/</code> 开头；如果不存在，则不能以空路径段开头，因为这样实际上就是以 <code>//</code> 开头，将被解释为 <code>authority</code> 权限组件。</li>
<li>可选的以 <code>?</code> 开头的 <code>query</code> 查询。语法没有明确要求，通常采用键值对的形式。</li>
<li>可选的以 <code>#</code> 开头的 <code>fragment</code> 片段。用于提供对次要资源的指向，例如在 HTML 文档中，将指向包含对应 <code>id</code> 属性的元素。</li>
</ul>
<h2 id="补齐-URL"><a href="#补齐-URL" class="headerlink" title="补齐 URL"></a>补齐 URL</h2><p>前面我们在使用 URL 时，并没有添加它的前缀例如 <code>https://</code>。那么我们具体使用的是 HTTP 协议还是 HTTPS 协议呢？</p>
<p>针对这种情况，浏览器有自己的预案，即默认使用 HTTP 协议。假如您是<strong>第一次</strong>访问我的博客（更严谨地说是第一次访问 <code>github.io</code> 域名下的网站），除非在输入的最开始就使用了 <code>https://lolipopj.github.io</code> 这个 URL，否则均会被默认补齐为 <code>http://lolipopj.github.io</code>。对于启用了 <a href="#%E4%BB%80%E4%B9%88%E6%98%AF-hsts%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E5%AE%83">HSTS 保护</a>的网站，从第二次的访问开始，浏览器将根据第一次访问时得到的响应结果，自动补齐协议。</p>
<p>随着 HSTS 的推广使用，现代浏览器中还内置了一个列表 <a href="#hsts-%E7%9A%84-preload-list-%E6%9C%BA%E5%88%B6">Preload List</a>，记录常用网站所使用的协议。对于这些网站，输入的 URL 将自动在前面补上记录的协议，再由浏览器发送请求。因此在实际情况中，第一次访问时，我们输入的 URL 就会被补齐为 <code>https://lolipopj.github.io</code>。</p>
<h3 id="HTTP-严格传输安全-HSTS"><a href="#HTTP-严格传输安全-HSTS" class="headerlink" title="HTTP 严格传输安全 HSTS"></a>HTTP 严格传输安全 HSTS</h3><p>以下内容主要参考此文章：</p>
<ul>
<li><a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/25537440">「HSTS详解」</a>，2017-03-03</li>
</ul>
<h3 id="什么是-HSTS，为什么我们需要它"><a href="#什么是-HSTS，为什么我们需要它" class="headerlink" title="什么是 HSTS，为什么我们需要它"></a>什么是 HSTS，为什么我们需要它</h3><p>在过去，假如服务器使用的是 HTTPS 协议，当我们默认使用 <code>http://lolipopj.github.io</code> 发起请求时，也会在服务器端通过 301 重定向到 <code>https://lolipopj.github.io</code>。在这个过程中，浏览器首先使用了 HTTP 协议发起请求，得到重定向的响应后，浏览器会重新发起基于 HTTPS 协议的请求并最终与服务器建立通信。</p>
<p>这是一个存在风险的操作，因为在建立 HTTPS 通信之前，我们有一次明文的 HTTP 请求以及重定向操作。HTTP 主要有如下不足：</p>
<ul>
<li>通信使用明文（不加密），内容可能会被窃听；</li>
<li>不验证通信方的身份，因此有可能遭遇伪装；</li>
<li>无法证明报文的完整性，所以有可能已遭篡改等。</li>
</ul>
<p>中间人可以劫持 HTTP 请求并篡改响应，阻止建立 HTTPS 连接，跳转到钓鱼网站等。</p>
<p>可以想见，对于使用 HTTPS 协议的服务器，如果能从第一次开始就直接以 HTTPS 协议建立连接，跳过 HTTP + 301 重定向的步骤，便可以避免这个潜在风险了。那么，浏览器该如何知道对于哪些网站应该使用 HTTP 协议，哪些网站应该建立 HTTPS 请求呢？</p>
<p>这就不得不提到 <strong>HSTS</strong>（HTTP Strict-Transport-Security，即 HTTP 严格传输安全）了，它是一个 Web 安全策略机制。其最核心的实现，是一个 HTTP 响应头，正是它让浏览器得知，接下来的一段时间（通常设置为 1 年），对这个域名的访问都应基于 HTTPS 协议。</p>
<p>例如，当浏览器通过 HTTP/HTTPS 协议访问某网站，返回的响应头可能包括一项：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Strict-Transport-Security: max-age=31536000; includeSubDomains</span><br></pre></td></tr></table></figure>

<p>浏览器就知道，在接下来的 31536000 秒（即 1 年）内，对该域名，以及子域名（includeSubDomains）的后续通信应该强制使用 HTTPS 进行，直到过了有效期（max-age）为止。每次相应都将刷新 HSTS 有效期；如果过了有效期，只要进行一次新的通信，又会开启一年的 HSTS 有效期。</p>
<h3 id="HSTS-加强浏览器连接保护"><a href="#HSTS-加强浏览器连接保护" class="headerlink" title="HSTS 加强浏览器连接保护"></a>HSTS 加强浏览器连接保护</h3><p>在 HSTS 出现以前，当浏览器发现当前网站的证书出现错误，或浏览器与服务器之间的通信不安全，或无法建立 HTTPS 连接时，浏览器会告警用户，但又允许用户继续不安全的访问。</p>
<p>从理论上来说，当出现此类告警时，用户应该提高警惕，终止后续的操作。然后现实是，绝大多数用户即使遇到这样的告警，也仍会继续访问。</p>
<p>HSTS 的出现使得事情出现了转机。对于启用了 HSTS 保护的网站，如果浏览器发现连接不安全，它将仅仅告警用户，<strong>不再</strong>提供继续访问的选择，进而避免后续的安全问题。</p>
<h3 id="HSTS-的-Preload-List-机制"><a href="#HSTS-的-Preload-List-机制" class="headerlink" title="HSTS 的 Preload List 机制"></a>HSTS 的 Preload List 机制</h3><p>很容易发现，在第一次通过 URL 访问网站时（或浏览器没有当前网站的 HSTS 信息时），仍会默认使用明文的 HTTP 协议进行请求，然后重定向切换到 HTTPS，并刷新浏览器中的 HSTS 信息。这样，用户还是有受到中间人攻击的风险。</p>
<p>针对这种情况，HSTS 的应对方法是：在浏览器中内置一个列表，即 Preload List，在这个列表中的域名，无论何种情况，浏览器将<strong>只使用</strong> HTTPS 发起连接。</p>
<p>这个列表由 Google Chromium 维护。</p>
<h3 id="加入到-HSTS-Preload-List"><a href="#加入到-HSTS-Preload-List" class="headerlink" title="加入到 HSTS Preload List"></a>加入到 HSTS Preload List</h3><p>为了加入到此列表，您的站点必须满足以下需求：</p>
<ol>
<li>提供有效的证书。</li>
<li>如果监听了 80 端口，则需要在同一主机上从 HTTP 重定向到 HTTPS。</li>
<li>为所有子域名提供 HTTPS 服务。</li>
<li>在根域名的 HTTP 响应头中添加 HSTS header。</li>
</ol>
<p>您可以在 <a target="_blank" rel="noopener" href="https://hstspreload.org/">HSTS Preload List 官网</a>提交申请，或是了解更多相关内容。</p>
<h2 id="通过-DNS-获取-IP-地址"><a href="#通过-DNS-获取-IP-地址" class="headerlink" title="通过 DNS 获取 IP 地址"></a>通过 DNS 获取 IP 地址</h2><p>TCP/IP 是能够在多个不同网络间实现信息传输的<strong>协议簇</strong>，它不仅仅指的是 TCP 和 IP 两个协议，而是指一个由 HTTP、HTTPS、FTP、SMTP、TCP、UDP 和 IP 等协议构成的协议簇。TCP/IP 定义了电子设备如何连入因特网，以及数据如何在它们之间传输的标准。</p>
<p>在 TCP/IP 概念层模型中，计算机网络体系结构自上而下分成了应用层、传输层、网络层和链路层。其中，HTTP 协议属于应用层。当客户端发出 HTTP 请求后，报文接下来将来到传输层和网络层进行处理。</p>
<p>浏览器会随机选用一个大于 1023（且 &lt;= 65535）的端口号，作为当前页面通讯使用的端口，以及传输层的 TCP 协议头的 Source Port 部分，这很容易实现。</p>
<p>但问题是，运输层的 IP 协议需要<strong>目标网站的 IP 地址</strong>才能工作，而现在浏览器只有 <code>https://lolipopj.github.io</code> 这个 URL 链接，它完全无法理解。</p>
<p>因此，浏览器将首先联系<strong>域名系统 DNS</strong>（Domain Name System），一个将域名和 IP 地址相互映射的分布式数据库。我们可以通过 DNS 来查询一串 URL 链接所对应的 IP 地址。</p>
<p>DNS 由客户端和服务端两部分组成，其中，客户端发起查询请求，例如查询域名的 IP 地址，服务端则负责回答域名的真正 IP 地址。那么现在，DNS 客户端发起查询 <code>github.io</code> 域名 IP 地址的请求，可能经过如下步骤：</p>
<ol>
<li>首先检查本机的 DNS 缓存，没有该域名的 IP 地址信息！</li>
<li>再查看本地硬盘中的 Host 文件，也没有！</li>
<li>请求本地域名服务器或公共域名服务器记录的信息。这里也没有！</li>
<li>此时，本地域名服务器或公共域名服务器会将查询请求发送给<strong>根域名服务器</strong>（Root name server）。根域名服务器会根据请求的 URL，将其对应的<strong>顶级域名服务器</strong>（Top-level domain server）的地址返回给本地域名服务器或公共域名服务器。例如，这里我们查询网址的顶级域名是 <code>.io</code>，则将此域名对应的顶级域名服务器的 IP 地址返回回来。</li>
<li>接着，本地域名服务器或公共域名服务器会将查询请求发送给刚刚得到的顶级域名服务器。顶级域名服务器将返回管理 <code>github.io</code> 的<strong>权威域名服务器</strong>的 IP 地址，例如 <code>185.199.110.153</code>。继续请求此权威域名服务器，如果得知 <code>lolipopj.github.io</code> 为此域名下的 A 记录，那么此 IP 地址即为所求。</li>
<li>查询的 IP 地址结果将缓存到本机以及本地域名服务器或公共域名服务器，用户下次查询时可以直接使用。</li>
</ol>
<p>通常情况下，大型网站都会返回 CNAME 记录，传递给<a href="#%E5%85%A8%E5%B1%80%E6%B5%81%E9%87%8F%E7%AE%A1%E7%90%86-gtm">全局流量管理 GTM 服务</a>，递归解析器将执行全新的 DNS 查找。通过 GTM 服务的负载均衡机制等，可以帮助用户找到最适合自己的访问的服务器 IP 地址；此外，大多数网站会做 CDN 缓存，GTM 服务也可以帮助用户找到最适合自己的 CDN 缓存服务器。</p>
<p>但无论如何，老天爷，浏览器可算是知道我博客的 IP 地址了。</p>
<h3 id="递归解析器"><a href="#递归解析器" class="headerlink" title="递归解析器"></a>递归解析器</h3><p>也称为 “DNS 解析器”。</p>
<p>递归解析器是 DNS 查询中的第一站。递归解析器作为客户端与 DNS 域名服务器的中间人。从 Web 客户端收到 DNS 查询后，递归解析器将使用缓存的数据进行响应，或者将向根域名服务器发送请求，接着向顶级域名服务器发送另一个请求，然后向权威域名服务器发送最后一个请求。收到来自包含已请求 IP 地址的权威域名服务器的响应后，递归解析器将向客户端发送响应。</p>
<p>大多数用户使用他们的 ISP 提供的递归解析器，即本地域名服务器。但也可以指定公共域名服务器作为递归解析器，如 Google 的 <code>8.8.8.8</code> 或 Cloudflare 的 <code>1.1.1.1</code> 等。</p>
<h3 id="根域名服务器"><a href="#根域名服务器" class="headerlink" title="根域名服务器"></a>根域名服务器</h3><ul>
<li><a target="_blank" rel="noopener" href="https://www.ruanyifeng.com/blog/2018/05/root-domain.html">「根域名的知识」</a>，2018-05-09</li>
</ul>
<p>根域名服务器中记录了各个顶级域名服务器的 IP 地址信息。</p>
<p>由于早期的 DNS 查询结果是一个 512 字节的 UDP 数据包，这个包最多容纳 13 个服务器的地址，因此规定全世界有 13 台根域名服务器，编号从 <code>a.root-servers.net</code> 到 <code>m.root-servers.net</code>。</p>
<p>为了保证根域名服务器的可用性，每台服务器又有多个节点。根据<a target="_blank" rel="noopener" href="https://root-servers.org/">此网站</a>的统计，截止 2021 年 07 月 12 日，全球一共有 1403 台根域名服务器实例。</p>
<p>当需要通过根域名服务器查询顶级域名服务器时，进行请求的 DNS 服务器会向这 13 台服务器<strong>同时</strong>发出请求，哪一个返回的信息先到达，则使用哪一个查询得到的结果。</p>
<h3 id="顶级域名服务器"><a href="#顶级域名服务器" class="headerlink" title="顶级域名服务器"></a>顶级域名服务器</h3><p>也称为 “TLD 域名服务器”。</p>
<p>顶级域名服务器负责管理在该顶级域名下注册的所有二级域名。或者说，顶级域名服务器中记录了属于它的各个权威域名服务器的 IP 地址。</p>
<h3 id="权威域名服务器"><a href="#权威域名服务器" class="headerlink" title="权威域名服务器"></a>权威域名服务器</h3><p>权威域名服务器是保存 DNS 名称记录（包括 A、AAAA 和 CNAME）的服务器。</p>
<p>权威域名服务器包含特定于其服务域名的信息。它可为递归解析器提供在 DNS A 记录中找到的服务器的 IP 地址；或者如果该域具有 CNAME 记录，它将为递归解析器提供一个别名域，这时递归解析器将必须执行全新 DNS 查找，以便从权威域名服务器获取记录（通常为包含 IP 地址的 A 记录）。</p>
<h3 id="DNS-支持-TCP-和-UDP-协议"><a href="#DNS-支持-TCP-和-UDP-协议" class="headerlink" title="DNS 支持 TCP 和 UDP 协议"></a>DNS 支持 TCP 和 UDP 协议</h3><ul>
<li><a target="_blank" rel="noopener" href="https://draveness.me/whys-the-design-dns-udp-tcp/">「为什么 DNS 使用 UDP 协议」</a></li>
</ul>
<blockquote>
<p>实际上，DNS 不仅使用了 UDP 协议，也使用了 TCP 协议，不过在具体介绍今天的问题之前，我们还是要对 DNS 协议进行简单的介绍：DNS 查询的类型不止包含 A 记录、CNAME 记录等常见查询，还包含 AXFR 类型的特殊查询，这种特殊查询主要用于 <strong>DNS 区域传输</strong>，它的作用就是在多个命名服务器之间快速迁移记录，由于查询返回的响应比较大，所以会使用 TCP 协议来传输数据包。<br>……<br>我们可以简单总结一下 DNS 的发展史，1987 年的 RFC1034 和 RFC1035 定义了最初版本的 DNS 协议，刚被设计出来的 DNS 就会同时使用 UDP 和 TCP 协议，对于绝大多数的 DNS 查询来说都会使用 UDP 数据报进行传输，TCP 协议只会在区域传输的场景中使用，其中 UDP 数据包只会传输最大 512 字节的数据，多余的会被截断；两年后发布的 RFC1123 预测了 DNS 记录中存储的数据会越来越多，同时也第一次显式的指出了<strong>发现 UDP 包被截断时应该通过 TCP 协议重试</strong>。<br>过了将近 20 年的时间，由于互联网的发展，人们发现 IPv4 已经不够分配了，所以<strong>引入了更长的 IPv6</strong>，DNS 也在 2003 年发布的 RFC3596 中进行了协议上的支持；随后发布的 RFC5011 和 RFC6376 增加了在鉴权和安全方面的支持，但是也带来了巨大的 DNS 记录，UDP 数据包被截断变得非常常见。<br>RFC6891 提供的 DNS 扩展机制能够帮助我们在一定程度上解决大数据包被截断的问题，减少了使用 TCP 协议进行重试的需要，但是由于<strong>最大传输单元的限制</strong>，这并不能解决所有问题。<br>DNS 出现之后的 30 多年，RFC7766 才终于提出了使用 TCP 协议作为主要协议来解决 UDP 无法解决的问题，TCP 协议也不再只是一种重试时使用的机制，随后出现的 DNS over TLS 和 DNS over HTTP 也都是对 DNS 协议的一种补充。</p>
</blockquote>
<h3 id="全局流量管理-GTM"><a href="#全局流量管理-GTM" class="headerlink" title="全局流量管理 GTM"></a>全局流量管理 GTM</h3><ul>
<li><a target="_blank" rel="noopener" href="https://help.aliyun.com/document_detail/189591.html?spm=a2c4g.11186623.6.640.3198229dgDSHXU">「全局流量管理产品原理」</a>，2020-12-11，阿里云</li>
</ul>
<blockquote>
<p>全局流量管理（GTM）支持用户就近接入、高并发负载均衡、健康检查与故障切换，可以帮助企业在短时间内构建同城多活与异地灾备的容灾架构。<br>GTM 属于 DNS 级别的服务，使用 DNS 向向用户返回特定的服务地址，然后客户端用户直接连接到服务地址。</p>
</blockquote>
<p>当递归解析器接收到响应的 CNAME 结果后，会再执行一遍 DNS 查找过程，得到 GTM 服务器的 IP 地址。递归解析器向 GTM 服务器发送请求，GTM 收到请求后，会根据运行机制和预配置策略向递归解析器响应最终应用服务的 IP 地址。</p>
<p>递归解析器将最后一次查询得到的 IP 地址作为访问 URL 的最终地址，返回给浏览器，同时缓存到本地。浏览器使用此 IP 地址直接向应用服务器发起网络连接，开始进行业务通信。</p>
<h2 id="通过-ARP-获取-MAC-地址"><a href="#通过-ARP-获取-MAC-地址" class="headerlink" title="通过 ARP 获取 MAC 地址"></a>通过 ARP 获取 MAC 地址</h2><ul>
<li><a target="_blank" rel="noopener" href="https://zh.wikipedia.org/wiki/%E5%9C%B0%E5%9D%80%E8%A7%A3%E6%9E%90%E5%8D%8F%E8%AE%AE">「地址解析协议」</a>，Wikipedia</li>
<li><a target="_blank" rel="noopener" href="https://blog.51cto.com/chenxinjie/1961255">「图解ARP协议（四）代理ARP：善意的欺骗」</a>，2017-09-01</li>
</ul>
<p>经过传输层和网络层封装后的包含有 HTTP 报文的数据包，现在来到了链路层。在这里，还将为它加上 MAC 头部。</p>
<blockquote>
<p>在<strong>以太网协议</strong>（在点对点协议 PPP 中，知道 IP 地址就可以进行通信；本文的讨论基于以太网协议）中规定，同一局域网中的一台主机要和另一台主机进行直接通信，必须要知道目标主机的 MAC 地址……另外，当发送主机和目的主机不在同一个局域网中时，即便知道对方的 MAC 地址，两者也不能直接通信，必须经过<strong>路由转发</strong>才可以。</p>
</blockquote>
<p>如何将已知的目标主机的 IP 地址，转换为数据链路传输需要的 MAC 地址？在 IPv4 中，这通过地址解析协议 ARP（Address Resolution Protocol）实现；在 IPv6 中，使用邻居发现协议 NDP（Neighbor Discovery Protocol）代替 ARP。</p>
<p>以 ARP 协议为例，它通过 ARP 请求和 ARP 响应报文确定 MAC 地址。ARP 请求报文是一种广播报文，<strong>局域网内</strong>的所有主机都可以收到。当某一个主机发现请求报文中的 IP 地址为自己的 IP 地址，就会发送 ARP 响应报文给发出请求报文的主机。</p>
<p>大多数情况下，我们需要与不在同一个局域网的主机通信，但由于每个网段都是独立的广播域，没法直接向互联网上的其它主机发送广播报文，该怎么办？网关设备就在这里大显身手了。</p>
<p>当主机<strong>已设置网关</strong>时，主机设置的网关设备将接收到 ARP 请求报文，以路由器为例：路由器发现 ARP 请求报文中的 IP 地址不属于当前局域网，就把自己的 MAC 地址响应给请求主机。后续请求主机直接使用这个 MAC 地址，将数据包传输给路由器。而数据包通过路由器的<strong>路由转发</strong>功能，最终顺利抵达互联网上对应 IP 地址的主机。</p>
<p>当主机<strong>未设置网关</strong>时，可以使用 <strong>代理 ARP</strong>（ARP Proxy）机制。局域网内的所有网关设备将接收到 ARP 请求报文，还是以路由器为例：路由器发现 ARP 请求报文中的 IP 地址不属于当前局域网，而是属于自己<strong>已知的</strong>另一个网段上的某台主机，就将自己作为代理，把自己的 MAC 地址响应给请求主机。后续请求主机直接使用这个 MAC 地址，通过路由器代理，就可以访问到局域网外的目标主机了。与 ARP 相比，代理 ARP 有如下局限：</p>
<ul>
<li>代理 ARP 需要有目标网关的信息；</li>
<li>代理 ARP 每次访问新的外网地址时，都需要发送一次 ARP 请求；</li>
<li>代理 ARP 受限于沿途网络设备。例如部分路由器可能不支持此功能，而支持此功能的路由器在默认情况下一般没有启用代理 ARP。</li>
</ul>
<p>在跨网段通信中，无论使用 ARP 还是代理 ARP，发出 ARP 请求的主机总会收到网关的 MAC 地址作为响应。</p>
<p>因此，在实际网络中，无论是局域网内通信，还是跨网段通信，绝大多数情况下还是使用的是 ARP，而非代理 ARP。代理 ARP 是对 ARP 的补充，是 ARP 的拓展使用。</p>
<p>言归正传，假如我们使用的是 IPv4 网络，通过 ARP 协议，我们将收到主机设置的网关设备的 MAC 地址，这样我们就顺利地为数据包添加了 MAC 头部。现在，完整的数据包就可以从主机传输到网关设备上，再驶入互联网的快车道，最终抵达服务器了。</p>
<h3 id="RARP-和-IARP"><a href="#RARP-和-IARP" class="headerlink" title="RARP 和 IARP"></a>RARP 和 IARP</h3><ul>
<li><a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/29081692">「图解ARP协议（六）RARP与IARP：被遗忘的兄弟协议」</a>，2017-09-05</li>
</ul>
<p>RARP 即反向 ARP（Reverse ARP），功能与 ARP 恰巧相反，用来实现 MAC 地址到 IP 地址的映射。</p>
<p>一个简单的例子是，当一台主机刚刚接入网络，这时它还没有局域网分配的内网 IP 地址。通过 RARP，它可以向局域网发送广播，广播包含自己的 MAC 地址，如果局域网内有 RARP 服务器且<strong>记录有此 MAC 地址的映射 IP 地址</strong>，那么它将接收到 RARP 响应，于是主机就拥有了自己的 IP 地址。</p>
<p>RARP 有这些特性：</p>
<ul>
<li>RARP 服务器必须提前绑定 MAC 地址和 IP 地址。如果没有提前绑定，则服务器不会发回响应；</li>
<li>RARP 服务器只能给请求的主机分配 IP 地址，不包括网关、DNS 等其它信息。</li>
</ul>
<p>在后来，有了启动协议 BOOTP，又有了现在最常用的<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol">动态主机设置协议 DHCP</a>。</p>
<blockquote>
<p>RARP 是一种逝去的地址分配技术，是 BOOTP 和 DHCP 的鼻祖，目前我们的电脑基本不会用到这个协议，只有部分无盘工作站等情况需要用到。</p>
</blockquote>
<p>IARP 即逆向 ARP（Inverse ARP），在帧中继网络（广域网）中实现 DLCI 到 IP 地址的映射。在帧中继网络中，它的功能<strong>类似于</strong>以太网中 MAC 地址到 IP 地址的映射。</p>
<p>随着广域网技术的更迭，帧中继技术正慢慢被被其它技术所替代。因此 IARP 作为帧中继技术中的一环，在现实中的使用也愈来愈少。</p>
<h2 id="使用-TLS-与服务器建立安全的-TCP-连接"><a href="#使用-TLS-与服务器建立安全的-TCP-连接" class="headerlink" title="使用 TLS 与服务器建立安全的 TCP 连接"></a>使用 TLS 与服务器建立安全的 TCP 连接</h2><p>在发送包含 HTTP 报文的数据包之前，客户端还要先通过三次握手与服务器建立 TCP 连接，这是为了保证数据传输的<strong>可靠性</strong>。在前面，我们已经得到了服务器的 MAC 地址，因此包含建立 TCP 连接请求报文的数据包可以顺利发送到服务器。</p>
<ol>
<li>TCP 第一次握手，客户端主动向服务器发送 TCP 请求报文。设置其首部：<code>SYN = 1, seq = x</code>。其中，x 和下面步骤中的 y 为随机值。</li>
<li>TCP 第二次握手，服务器监听请求，当接收到客户端的请求报文时，若同意连接请求，则发回确认报文。设置其首部：<code>SYN = 1, ACK = 1, ack = x + 1, seq = y</code>。</li>
<li>TCP 第三次握手，客户端收到确认报文，通知上层应用（即我们的浏览器）连接已建立，并向服务器发送确认报文。设置其首部：<code>ACK = 1, ack = y + 1</code>。服务器接收到确认报文后，也通知其上层应用连接已建立。</li>
</ol>
<p>由于前面我们提到的 HSTS 机制，我们的 HTTP 请求将基于 HTTPS 协议。严格来说，HTTPS 并非应用层的一种新协议，它只是将 HTTP 协议的<strong>通信接口</strong>部分使用<strong>传输层安全性协议 TLS</strong>（Transport Layer Security）代替罢了。通常，HTTP 直接与 TCP 通信。当使用 TLS 时，HTTP 先与 TLS 通信，再由 TLS 与 TCP 通信。</p>
<p>在这种情况下，为了保证数据传输的<strong>安全性</strong>，客户端还要与服务器协商 TLS 协议参数，这个过程通常称为 TLS 握手。在 TLS 1.0, 1.1 及 1.2 版本中，握手有四次；而在 TLS 1.3 版本中，握手只需要三次。TLS 握手是在 TCP 连接建立之后进行的。</p>
<p>以 <a target="_blank" rel="noopener" href="https://datatracker.ietf.org/doc/html/rfc8446">TLS 1.3 协议</a>为例，握手过程如下所示：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">       Client                                           Server</span><br><span class="line"></span><br><span class="line">Key  ^ ClientHello</span><br><span class="line">Exch | + key_share*</span><br><span class="line">     | + signature_algorithms*</span><br><span class="line">     | + psk_key_exchange_modes*</span><br><span class="line">     v + pre_shared_key*       --------&gt;</span><br><span class="line">                                                  ServerHello  ^ Key</span><br><span class="line">                                                 + key_share*  | Exch</span><br><span class="line">                                            + pre_shared_key*  v</span><br><span class="line">                                        &#123;EncryptedExtensions&#125;  ^  Server</span><br><span class="line">                                        &#123;CertificateRequest*&#125;  v  Params</span><br><span class="line">                                               &#123;Certificate*&#125;  ^</span><br><span class="line">                                         &#123;CertificateVerify*&#125;  | Auth</span><br><span class="line">                                                   &#123;Finished&#125;  v</span><br><span class="line">                               &lt;--------  [Application Data*]</span><br><span class="line">     ^ &#123;Certificate*&#125;</span><br><span class="line">Auth | &#123;CertificateVerify*&#125;</span><br><span class="line">     v &#123;Finished&#125;              --------&gt;</span><br><span class="line">       [Application Data]      &lt;-------&gt;  [Application Data]</span><br><span class="line"></span><br><span class="line">              +  Indicates noteworthy extensions sent in the</span><br><span class="line">                 previously noted message.</span><br><span class="line"></span><br><span class="line">              *  Indicates optional or situation-dependent</span><br><span class="line">                 messages/extensions that are not always sent.</span><br><span class="line"></span><br><span class="line">              &#123;&#125; Indicates messages protected using keys</span><br><span class="line">                 derived from a [sender]_handshake_traffic_secret.</span><br><span class="line"></span><br><span class="line">              [] Indicates messages protected using keys</span><br><span class="line">                 derived from [sender]_application_traffic_secret_N.</span><br></pre></td></tr></table></figure>

<p>这样，我们的客户端和服务器建立了基于 TLS 1.3 的安全 TCP 连接，是时候传输数据了！</p>
<h3 id="TLS-与-SSL"><a href="#TLS-与-SSL" class="headerlink" title="TLS 与 SSL"></a>TLS 与 SSL</h3><ul>
<li><a target="_blank" rel="noopener" href="https://zh.wikipedia.org/wiki/%E5%82%B3%E8%BC%B8%E5%B1%A4%E5%AE%89%E5%85%A8%E6%80%A7%E5%8D%94%E5%AE%9A">「传输层安全性协议」</a>，Wikipedia</li>
</ul>
<p>在日常使用中，我们经常会说 SSL 或 TLS/SSL，那么 TLS 和 SSL 之间有什么关系呢？</p>
<p>原来，<strong>安全套接层 SSL</strong>（Secure Sockets Layer） 是 TLS 的前身。TLS 基于 SSL 3.0 协议，是 SSL 协议标准化后的协议名。由于 SSL 3.0 设计中的缺陷，在 2015 年 6 月，<a target="_blank" rel="noopener" href="https://datatracker.ietf.org/doc/html/rfc7568">RFC 7568</a> 宣布弃用 SSL 3.0。</p>
<p>目前最新的 TLS 1.3 协议在 2018 年 8 月发表的 <a target="_blank" rel="noopener" href="https://datatracker.ietf.org/doc/html/rfc8446">RFC 8446</a> 中定义。而较老的 TLS 1.0 和 TLS 1.1 也已于 2021 年 3 月，在 <a target="_blank" rel="noopener" href="https://datatracker.ietf.org/doc/html/rfc8996">RFC 8996</a> 中宣告被弃用。</p>
<p>结论是，理论上我们现在用的加密协议大抵都是 TLS，在讨论中直接使用 TLS 即可。</p>
<h3 id="TLS-1-3-的进步"><a href="#TLS-1-3-的进步" class="headerlink" title="TLS 1.3 的进步"></a>TLS 1.3 的进步</h3><ul>
<li><a target="_blank" rel="noopener" href="https://blog.cloudflare.com/rfc-8446-aka-tls-1-3/">「A Detailed Look at RFC 8446 (a.k.a. TLS 1.3)」</a>，2018-08-11</li>
</ul>
<p>TLS 已经存在相当多的问题：例如代码缺乏测试，稳健性较低；存在许多设计缺陷，出现很多漏洞等。</p>
<p>在近些年来，互联网上一直存在一个主要趋势，即全面启用 HTTPS。这可以保护用户的安全，但会导致连接速度变慢。自 TLS 标准化以来，在发送加密数据之前，客户端到服务器的握手请求会进行两次往返（或者会话恢复连接时进行一次往返）。与单独的 HTTP 相比，HTTPS 中 TLS 握手的额外成本可能带来潜在的问题，并对以性能为中心的应用产生负面影响。在 <a target="_blank" rel="noopener" href="https://datatracker.ietf.org/doc/html/rfc5246">TLS 1.2 协议</a>中，握手过程如下所示：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">Client                                                Server</span><br><span class="line"></span><br><span class="line">ClientHello                   --------&gt;</span><br><span class="line">                                                 ServerHello</span><br><span class="line">                                                Certificate*</span><br><span class="line">                                          ServerKeyExchange*</span><br><span class="line">                                         CertificateRequest*</span><br><span class="line">                              &lt;--------      ServerHelloDone</span><br><span class="line">Certificate*</span><br><span class="line">ClientKeyExchange</span><br><span class="line">CertificateVerify*</span><br><span class="line">[ChangeCipherSpec]</span><br><span class="line">Finished                      --------&gt;</span><br><span class="line">                                          [ChangeCipherSpec]</span><br><span class="line">                              &lt;--------             Finished</span><br><span class="line">Application Data              &lt;-------&gt;     Application Data</span><br><span class="line"></span><br><span class="line">* Indicates optional or situation-dependent messages that are not</span><br><span class="line">always sent.</span><br></pre></td></tr></table></figure>

<p>IETF 对 TLS 1.2 的过时设计和两次往返开销不满意，着手定义新版本的 TLS，即 TLS 1.3，旨在解决如下的主要问题：</p>
<ul>
<li>减少握手延迟；</li>
<li>加密更多的握手信息；</li>
<li>提高对跨协议攻击的恢复能力；</li>
<li>删除遗留的功能。</li>
</ul>
<p>在过去的二十年里，对密码学的研究帮助人们学到更多关于如何编写<strong>更安全的加密协议</strong>的知识。TLS 1.3 的设计目标之一就是删除潜在的危险元素，纠正过去的错误设计。例如：</p>
<ul>
<li><strong>移除 RSA 密钥交换模式</strong>，仅保留 Diffie-Hellman（下简称 DH）密钥协议。RSA 模式存在两个严重的问题，一是它不是前向加密（forward secret），意味着如果有人记录下加密的会话，如果在某天获取到服务器的私钥，就可以对会话进行破解。二是存在难以修复的漏洞，可以参见 <a target="_blank" rel="noopener" href="https://robotattack.org/">ROBOT 攻击</a>。删除 RSA 模式，只保留 DH 密钥协议，带来了一些性能优势，我们在后面进行讨论。</li>
<li><strong>提供更少的可选项</strong>。在密码学中，提供太多的选项可能导致更多的错误。这个原则在选择 DH 密钥协议的参数时尤为明显。该协议的安全性取决于选择的 DH 参数值，它一方面要为较大的值，另一方面需要具有某些<a target="_blank" rel="noopener" href="https://arstechnica.com/information-technology/2016/01/high-severity-bug-in-openssl-allows-attackers-to-decrypt-https-traffic/">正确的数学属性</a>。在以前版本的 TLS 中，DH 参数由参与者决定；而在 TLS 1.3 版本中，则将参数限制为已知安全的值，减少用户的可选项。</li>
</ul>
<p>更多关于安全性的改进可以访问该小节开头的<a target="_blank" rel="noopener" href="https://blog.cloudflare.com/rfc-8446-aka-tls-1-3/">参考博客</a>。下面我们来看看 TLS 1.3 在<strong>性能表现上的优势</strong>。</p>
<p>在 DH 密钥协议中，客户端和服务器都从创建公钥-私钥对开始，然后交换各自的公钥，并根据自己的私钥和对方的公钥生成最终的密钥。最终的密钥自始至终都不会通过网络传输，DH 算法通过数学定律保证双方算出的结果一致。接下来，客户端和服务器就可以使用这个密钥对数据进行加密和解密。</p>
<p>TLS 1.3 使用这样一个更简单的密钥协商模式和一组更少的密钥协商选项，这意味着每个连接都将使用基于 DH 的密钥协议，服务器支持的 DH 参数更容易被猜到。有限的选择使得客户端可以在第一条消息中就发送自己的公钥，而无需等待服务器确认支持的类型。</p>
<p>在服务器不支持客户端使用协商选项的罕见情况下，服务器可以发送 <code>HelloRetryRequest</code> 的消息，让客户端知道自己支持哪些协商选项组。</p>
<p>作为小结：</p>
<blockquote>
<p>TLS 1.3 is a modern security protocol built with modern tools like formal analysis that retains its backwards compatibility. It has been tested widely and iterated upon using real world deployment data. It’s a cleaner, faster, and more secure protocol ready to become the de facto two-party encryption protocol online.<br>It is one the best recent examples of how it is possible to take 20 years of deployed legacy code and change it on the fly, resulting in a better internet for everyone. TLS 1.3 has been debated and analyzed for the last three years (2015 - 2018) and it’s now ready for prime time.</p>
</blockquote>
<h3 id="对称密钥加密，非对称密钥加密与混合加密"><a href="#对称密钥加密，非对称密钥加密与混合加密" class="headerlink" title="对称密钥加密，非对称密钥加密与混合加密"></a>对称密钥加密，非对称密钥加密与混合加密</h3><p>简单来说，在<strong>对称密钥加密</strong>中，对数据的加密和解密都使用同一个密钥。相较于非对称密钥加密，它的速度更快；但是由于密钥在传输过程中容易被获取，因此其安全性较低。</p>
<p>在<strong>非对称密钥加密</strong>（或公开密钥加密）中，使用一对密钥进行加密和解密，分别为公开密钥和私有密钥。公开密钥所有人都可以获得，客户端使用公开密钥对数据进行加密，服务器使用私有密钥对数据进行解密。同样，服务器对响应的数据使用私有密钥加密，客户端则可以通过公开密钥进行解密。相较于对称密钥加密，只要保管好私有密钥，就能保证客户端传输的消息不被破解，因此它的安全性更高；由于算法和过程更为繁琐，因此其速度较慢。</p>
<p>HTTPS 采用的是<strong>混合加密</strong>机制——在 TLS 1.3 以前，客户端首先使用服务器提供的公钥，加密一个随机值，然后将它传输给服务器。服务器使用私钥解密，获得随机值，然后使用与客户端相同的密钥生成算法，基于这个随机值和之前握手中创建的另外两个随机值，生成与客户端相同的密钥，之后客户端和服务器就可以使用这把对称密钥进行通信了。在 TLS 1.3 中，基于 DH 密钥协议，不再赘述。这样，客户端和服务器之间的通信就兼顾了对称密钥加密的高效性和非对称密钥加密的安全性。</p>
<h2 id="欢迎访问我的博客"><a href="#欢迎访问我的博客" class="headerlink" title="欢迎访问我的博客"></a>欢迎访问我的博客</h2><p>现在，浏览器知道了已经与远方的服务器建立好了安全可靠的传输通道，于是将 HTTP 请求信息打包好，传输到服务器上的 443 端口。服务器使用密钥解密获得其中的信息，发现是请求我博客的 HTTP 报文，遂转发给相应的 HTTP 服务。最终将我们所需的 HTML, CSS, JS 以及相关的静态文件发送给浏览器，浏览器再把它们渲染出来。</p>
<p>Oh, Welcome to visit my blog！</p>
<h2 id="参考文章"><a href="#参考文章" class="headerlink" title="参考文章"></a>参考文章</h2><p>除了正文中特别罗列出来的网站文章，还包括：</p>
<ul>
<li><a target="_blank" rel="noopener" href="https://www.zhihu.com/question/34873227/answer/518086565">「在浏览器地址栏输入一个URL后回车，背后会进行哪些技术步骤？」</a>，2020-03-28</li>
<li><a target="_blank" rel="noopener" href="https://segmentfault.com/a/1190000021000934">「上古面试题——浏览器地址栏输入后回车会发生什么」</a>，2019-11-14</li>
<li><a target="_blank" rel="noopener" href="https://segmentfault.com/a/1190000039650564">「搞懂这 9 步，DNS 访问原理就明明白白了」</a>，2021-03-17</li>
<li><a target="_blank" rel="noopener" href="https://segmentfault.com/a/1190000039406281">「DNS查询机制」</a>，2021-03-13</li>
<li><a target="_blank" rel="noopener" href="https://www.cloudflare.com/zh-cn/learning/dns/dns-server-types/">「DNS 服务器有哪些不同类型？」</a>，Cloudflare</li>
<li><a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/379015679">「36 张图详解 ARP ：网络世界没有我，你哪也别想去」</a>，2021-06-08</li>
<li><a target="_blank" rel="noopener" href="https://www.ituring.com.cn/book/1229">「图解HTTP」</a>，[日]上野宣 著，于均良 译</li>
<li><a target="_blank" rel="noopener" href="https://ocdman.github.io/2018/11/02/%E8%AF%A6%E8%A7%A3TCP%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B%E4%BB%A5%E5%8F%8ATLS-SSL%E6%8F%A1%E6%89%8B/">「详解TCP三次握手以及TLS/SSL握手」</a>，2018-11-02</li>
<li><a target="_blank" rel="noopener" href="https://segmentfault.com/a/1190000021559557">「HTTPS详解二：SSL / TLS 工作原理和详细握手过程」</a>，2020-01-19</li>
</ul>

    </article>
    <!-- license -->
    
        <div class="license-wrapper">
            <p>原文作者：<a href="https://LolipopJ.github.io">Lolipop</a>
            <p>原文链接：<a href="https://lolipopj.github.io/2021/07/07/browser-behind-visit-url/">https://lolipopj.github.io/2021/07/07/browser-behind-visit-url/</a>
            <p>发表日期：<a href="https://lolipopj.github.io/2021/07/07/browser-behind-visit-url/">July 7th 2021, 4:00:00 pm</a>
            <p>更新日期：<a href="https://lolipopj.github.io/2021/07/07/browser-behind-visit-url/">July 22nd 2021, 4:00:00 pm</a>
            <p>版权声明：本文采用<a rel="license noopener" target="_blank" href="http://creativecommons.org/licenses/by-nc/4.0/">知识共享署名-非商业性使用 4.0 国际许可协议</a>进行许可</p>
        </div>
    
    <!-- paginator -->
    <ul class="post-paginator">
        <li class="next">
            
                <div class="nextSlogan">Next Post</div>
                <a href="/2021/07/09/switch-travis-to-github-workflow/" title="更换持续集成工具，从 Travis 到 Github Actions">
                    <div class="nextTitle">更换持续集成工具，从 Travis 到 Github Actions</div>
                </a>
            
        </li>
        <li class="previous">
            
                <div class="prevSlogan">Previous Post</div>
                <a href="/2021/06/25/web-font-for-hexo-theme-archer/" title="为 Archer 主题更换字体">
                    <div class="prevTitle">为 Archer 主题更换字体</div>
                </a>
            
        </li>
    </ul>
    <!-- comment -->
    
        <div class="post-comment">
            <!-- 来必力 City 版安装代码 -->


            

            

            
    <div id="gitalk-container"></div>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@1.7.2/dist/gitalk.css">
    <script src="https://cdn.jsdelivr.net/npm/gitalk@1.7.2/dist/gitalk.min.js"></script>
    <script>
        let idOption = 'Wed Jul 07 2021 16:00:00 GMT+0000'
        
            idOption = location.pathname
        
        const gitalk = new Gitalk({
            clientID: '3e27d4e7935138a80cd8',
            clientSecret: 'cd3eda2bf0740e7a51b8b611ade908eb95590e45',
            repo: 'LolipopJ.github.io',
            owner: 'LolipopJ',
            admin: ["LolipopJ"],
            id: idOption,
            distractionFreeMode: false,
            createIssueManually: false,
        })
        gitalk.render('gitalk-container')
    </script>
    <noscript>为正常使用 Gitalk 评论功能，您需要激活 JavaScript</noscript>


            <!-- utteranc评论 -->


            <!-- partial('_partial/comment/changyan') -->
            <!--PC版-->


            
            

            

        </div>
    
    <!-- timeliness note -->
    <!-- idea from: https://hexo.fluid-dev.com/posts/hexo-injector/#%E6%96%87%E7%AB%A0%E6%97%B6%E6%95%88%E6%80%A7%E6%8F%90%E7%A4%BA -->
    
    <!-- Mathjax -->
    
</main>

                <!-- profile -->
                
            </div>
            <footer class="footer footer-unloaded">
    <!-- social  -->
    
        <div class="social">
            
    
        
            
                <a href="mailto:lolipop0703@qq.com" class="iconfont-archer email" title=email ></a>
            
        
    
        
            
                <a href="//github.com/LolipopJ" class="iconfont-archer github" target="_blank" title=github></a>
            
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
            
                <a href="https://twitter.com/Lolipop_0703" class="iconfont-archer twitter" target="_blank" title=twitter></a>
            
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
            
                <a href="/atom.xml" class="iconfont-archer rss" target="_blank" title=rss></a>
            
        
    


        </div>
    
    <!-- powered by Hexo  -->
    <div class="copyright">
        <span id="hexo-power">Powered by <a href="https://hexo.io/" target="_blank">Hexo</a></span><span class="iconfont-archer power">&#xe635;</span><span id="theme-info">theme <a href="https://github.com/fi3ework/hexo-theme-archer" target="_blank">Archer</a></span>
    </div>
    <!-- website approve for Chinese user -->
    
        <div class="website-approve">
            
                <span id="icp-approve" class="icp-approve">
                    <a href="https://beian.miit.gov.cn/" target="_blank">蜀ICP备 2021015698号</a>
                </span>
            
            
                
                <img class="beian-img" src="/assets/beian.png" />
                <span id="beian-approve" class="beian-approve">
                    <a href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=51010802001109" target="_blank">京公网安备 51010802001109号</a>
                </span>
            
        </div>
    
    <!-- 不蒜子  -->
    
        <div class="busuanzi-container">
            
             
                <span id="busuanzi_container_site_pv">PV: <span id="busuanzi_value_site_pv"></span> :)</span>
            
        </div>
    	
</footer>

        </div>
        <!-- toc -->
        
            <div class="toc-wrapper toc-wrapper-loding" style=







    top:50vh;

>
                <div class="toc-catalog">
                    <span class="iconfont-archer catalog-icon">&#xe613;</span><span>CATALOG</span>
                </div>
                <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%A3%80%E6%9F%A5-URL-%E6%A0%BC%E5%BC%8F"><span class="toc-number">1.</span> <span class="toc-text">检查 URL 格式</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BB%80%E4%B9%88%E6%98%AF-URL"><span class="toc-number">1.1.</span> <span class="toc-text">什么是 URL</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#URL-%E6%A0%BC%E5%BC%8F"><span class="toc-number">1.2.</span> <span class="toc-text">URL 格式</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%A1%A5%E9%BD%90-URL"><span class="toc-number">2.</span> <span class="toc-text">补齐 URL</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#HTTP-%E4%B8%A5%E6%A0%BC%E4%BC%A0%E8%BE%93%E5%AE%89%E5%85%A8-HSTS"><span class="toc-number">2.1.</span> <span class="toc-text">HTTP 严格传输安全 HSTS</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BB%80%E4%B9%88%E6%98%AF-HSTS%EF%BC%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E5%AE%83"><span class="toc-number">2.2.</span> <span class="toc-text">什么是 HSTS，为什么我们需要它</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#HSTS-%E5%8A%A0%E5%BC%BA%E6%B5%8F%E8%A7%88%E5%99%A8%E8%BF%9E%E6%8E%A5%E4%BF%9D%E6%8A%A4"><span class="toc-number">2.3.</span> <span class="toc-text">HSTS 加强浏览器连接保护</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#HSTS-%E7%9A%84-Preload-List-%E6%9C%BA%E5%88%B6"><span class="toc-number">2.4.</span> <span class="toc-text">HSTS 的 Preload List 机制</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8A%A0%E5%85%A5%E5%88%B0-HSTS-Preload-List"><span class="toc-number">2.5.</span> <span class="toc-text">加入到 HSTS Preload List</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%80%9A%E8%BF%87-DNS-%E8%8E%B7%E5%8F%96-IP-%E5%9C%B0%E5%9D%80"><span class="toc-number">3.</span> <span class="toc-text">通过 DNS 获取 IP 地址</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%80%92%E5%BD%92%E8%A7%A3%E6%9E%90%E5%99%A8"><span class="toc-number">3.1.</span> <span class="toc-text">递归解析器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%A0%B9%E5%9F%9F%E5%90%8D%E6%9C%8D%E5%8A%A1%E5%99%A8"><span class="toc-number">3.2.</span> <span class="toc-text">根域名服务器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%A1%B6%E7%BA%A7%E5%9F%9F%E5%90%8D%E6%9C%8D%E5%8A%A1%E5%99%A8"><span class="toc-number">3.3.</span> <span class="toc-text">顶级域名服务器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9D%83%E5%A8%81%E5%9F%9F%E5%90%8D%E6%9C%8D%E5%8A%A1%E5%99%A8"><span class="toc-number">3.4.</span> <span class="toc-text">权威域名服务器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#DNS-%E6%94%AF%E6%8C%81-TCP-%E5%92%8C-UDP-%E5%8D%8F%E8%AE%AE"><span class="toc-number">3.5.</span> <span class="toc-text">DNS 支持 TCP 和 UDP 协议</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%A8%E5%B1%80%E6%B5%81%E9%87%8F%E7%AE%A1%E7%90%86-GTM"><span class="toc-number">3.6.</span> <span class="toc-text">全局流量管理 GTM</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%80%9A%E8%BF%87-ARP-%E8%8E%B7%E5%8F%96-MAC-%E5%9C%B0%E5%9D%80"><span class="toc-number">4.</span> <span class="toc-text">通过 ARP 获取 MAC 地址</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#RARP-%E5%92%8C-IARP"><span class="toc-number">4.1.</span> <span class="toc-text">RARP 和 IARP</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8-TLS-%E4%B8%8E%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%BB%BA%E7%AB%8B%E5%AE%89%E5%85%A8%E7%9A%84-TCP-%E8%BF%9E%E6%8E%A5"><span class="toc-number">5.</span> <span class="toc-text">使用 TLS 与服务器建立安全的 TCP 连接</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#TLS-%E4%B8%8E-SSL"><span class="toc-number">5.1.</span> <span class="toc-text">TLS 与 SSL</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#TLS-1-3-%E7%9A%84%E8%BF%9B%E6%AD%A5"><span class="toc-number">5.2.</span> <span class="toc-text">TLS 1.3 的进步</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AF%B9%E7%A7%B0%E5%AF%86%E9%92%A5%E5%8A%A0%E5%AF%86%EF%BC%8C%E9%9D%9E%E5%AF%B9%E7%A7%B0%E5%AF%86%E9%92%A5%E5%8A%A0%E5%AF%86%E4%B8%8E%E6%B7%B7%E5%90%88%E5%8A%A0%E5%AF%86"><span class="toc-number">5.3.</span> <span class="toc-text">对称密钥加密，非对称密钥加密与混合加密</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%AC%A2%E8%BF%8E%E8%AE%BF%E9%97%AE%E6%88%91%E7%9A%84%E5%8D%9A%E5%AE%A2"><span class="toc-number">6.</span> <span class="toc-text">欢迎访问我的博客</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8F%82%E8%80%83%E6%96%87%E7%AB%A0"><span class="toc-number">7.</span> <span class="toc-text">参考文章</span></a></li></ol>
            </div>
        
        <!-- sidebar -->
        <div class="sidebar sidebar-hide">
    <ul class="sidebar-tabs sidebar-tabs-active-0">
        <li class="sidebar-tab-archives"><span class="iconfont-archer">&#xe67d;</span><span class="tab-name">Archive</span></li>
        <li class="sidebar-tab-tags"><span class="iconfont-archer">&#xe61b;</span><span class="tab-name">Tag</span></li>
        <li class="sidebar-tab-categories"><span class="iconfont-archer">&#xe666;</span><span class="tab-name">Cate</span></li>
    </ul>
    <div class="sidebar-content sidebar-content-show-archive">
        <div class="sidebar-panel-archives">
    <!-- 在 ejs 中将 archive 按照时间排序 -->
    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    
    
    
    
    <div class="total-and-search">
        <div class="total-archive">
        Total : 31
        </div>
        <!-- search  -->
        
            <div class="site-search site-search-loading popup-trigger">
                <span class="iconfont-archer search-icon">&#xe627;</span>
            </div>
        
    </div>
    
    <div class="post-archive">
    
        
            
            
            <div class="archive-year"> 2022 </div>
            <ul class="year-list">
            
        
        <li class="archive-post-item">
            <span class="archive-post-date">02/12</span>
            <a class="archive-post-title" href="/2022/02/11/connect-with-pgsql/">连接到 Windows 端的 PostgreSQL 数据库</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">01/13</span>
            <a class="archive-post-title" href="/2022/01/12/random-get-me-a-picture/">这位客官，要来一张我珍藏许久的图片吗</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">01/09</span>
            <a class="archive-post-title" href="/2022/01/08/start-telegram-bot/">从零开始使用 Telegram Bot</a>
        </li>
    
        
            
            
                
                </ul>
            
            <div class="archive-year"> 2021 </div>
            <ul class="year-list">
            
        
        <li class="archive-post-item">
            <span class="archive-post-date">08/19</span>
            <a class="archive-post-title" href="/2021/08/18/build-my-resume/">把自己的简历做成 Web 页面</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">08/13</span>
            <a class="archive-post-title" href="/2021/08/12/github-jsdelivr-hold-image/">使用 jsDelivr 加速 Github 仓库搭建自己的图床服务</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">08/07</span>
            <a class="archive-post-title" href="/2021/08/06/editorconfig-prettier/">使用 EditorConfig 和 Prettier 优雅地配置 VSCode 代码格式化</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">07/10</span>
            <a class="archive-post-title" href="/2021/07/09/switch-travis-to-github-workflow/">更换持续集成工具，从 Travis 到 Github Actions</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">07/08</span>
            <a class="archive-post-title" href="/2021/07/07/browser-behind-visit-url/">在浏览器中输入 URL 到显示网页，背后发生了什么</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">06/26</span>
            <a class="archive-post-title" href="/2021/06/25/web-font-for-hexo-theme-archer/">为 Archer 主题更换字体</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">06/25</span>
            <a class="archive-post-title" href="/2021/06/24/website-deployment-docker-nginx/">使用基于 Docker 的 Nginx 部署静态网页项目</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">06/09</span>
            <a class="archive-post-title" href="/2021/06/08/linux-project-v/">在 Linux 系统下启用 Project-V</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">06/04</span>
            <a class="archive-post-title" href="/2021/06/03/euler-install-mysql/">在 Euler 系统上离线安装 MySQL 5.7</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">05/20</span>
            <a class="archive-post-title" href="/2021/05/19/js-use-class/">漫谈 JavsScript 类（Class）的使用</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">05/18</span>
            <a class="archive-post-title" href="/2021/05/17/js-closure/">漫谈 JavsScript 闭包</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">05/11</span>
            <a class="archive-post-title" href="/2021/05/10/js-hoisting/">JavsScript 变量提升和函数提升</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">05/08</span>
            <a class="archive-post-title" href="/2021/05/07/js-debounce-throttle/">函数防抖和节流，以及在 Vue 中的运用</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">04/26</span>
            <a class="archive-post-title" href="/2021/04/25/windows-install-grpc/">Windows 系统编译安装基于 C++ 的 gRPC</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">04/22</span>
            <a class="archive-post-title" href="/2021/04/21/linux-docker-install-grpc/">Linux 系统编译安装基于 C++ 的 gRPC</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">04/20</span>
            <a class="archive-post-title" href="/2021/04/19/linux-docker-gcc-update/">Linux 容器更新或降级 GCC 版本</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">03/29</span>
            <a class="archive-post-title" href="/2021/03/28/protobuf-learning/">Protobuf 学习笔记</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">03/17</span>
            <a class="archive-post-title" href="/2021/03/16/amap-import-vue/">在 Nuxt.js 中引入高德地图并实现定位及逆地理编码</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">03/16</span>
            <a class="archive-post-title" href="/2021/03/15/tencent-map-api-get-current-location/">使用腾讯位置服务进行 Web 前端定位</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">03/10</span>
            <a class="archive-post-title" href="/2021/03/09/xxx-is-not-a-symbolic-link/">提示 *** is not a symbolic link 解决方案</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">03/03</span>
            <a class="archive-post-title" href="/2021/03/02/nodejs-eslint-prettier/">Nuxt 项目配置 ESLint 和 Prettier 检查并规范代码质量与格式</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">02/23</span>
            <a class="archive-post-title" href="/2021/02/22/write-md-parser/">Webpack 读取本地 Markdown 文件并进行预处理</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">02/21</span>
            <a class="archive-post-title" href="/2021/02/20/tg-mtproto-one-click/">一键安装并配置 MTProto Proxy 代理 Telegram</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">02/19</span>
            <a class="archive-post-title" href="/2021/02/18/hexo-github-actions-ci-cd/">使用 Github Actions 持续集成与部署 Hexo 博客</a>
        </li>
    
        
            
            
                
                </ul>
            
            <div class="archive-year"> 2020 </div>
            <ul class="year-list">
            
        
        <li class="archive-post-item">
            <span class="archive-post-date">12/29</span>
            <a class="archive-post-title" href="/2020/12/28/ISO-IEC-IEEE-42010-des/">IEEE 1471（ISO/IEC/IEEE 42010）架构描述方法</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">09/28</span>
            <a class="archive-post-title" href="/2020/09/27/pytorch-install-windows-10/">PyTorch 在 Windows 10 系统下的环境配置及安装</a>
        </li>
    
        
            
            
                
                </ul>
            
            <div class="archive-year"> 2019 </div>
            <ul class="year-list">
            
        
        <li class="archive-post-item">
            <span class="archive-post-date">12/27</span>
            <a class="archive-post-title" href="/2019/12/26/archer-theme-update-log/">基于 Archer 主题的博客开发</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">12/27</span>
            <a class="archive-post-title" href="/2019/12/26/hello-hexo-world/">Hello Hexo World</a>
        </li>
    
    </div>
</div>

        <div class="sidebar-panel-tags">
    <div class="sidebar-tags-name">
        
            <span class="sidebar-tag-name" data-tags="开发日志">
                <span class="iconfont-archer">&#xe606;</span>
                开发日志
            </span>
        
            <span class="sidebar-tag-name" data-tags="Vue-2">
                <span class="iconfont-archer">&#xe606;</span>
                Vue-2
            </span>
        
            <span class="sidebar-tag-name" data-tags="软件体系架构设计">
                <span class="iconfont-archer">&#xe606;</span>
                软件体系架构设计
            </span>
        
            <span class="sidebar-tag-name" data-tags="JavaScript">
                <span class="iconfont-archer">&#xe606;</span>
                JavaScript
            </span>
        
            <span class="sidebar-tag-name" data-tags="Node">
                <span class="iconfont-archer">&#xe606;</span>
                Node
            </span>
        
            <span class="sidebar-tag-name" data-tags="Nuxt">
                <span class="iconfont-archer">&#xe606;</span>
                Nuxt
            </span>
        
            <span class="sidebar-tag-name" data-tags="Promise">
                <span class="iconfont-archer">&#xe606;</span>
                Promise
            </span>
        
            <span class="sidebar-tag-name" data-tags="博客开发">
                <span class="iconfont-archer">&#xe606;</span>
                博客开发
            </span>
        
            <span class="sidebar-tag-name" data-tags="Hexo">
                <span class="iconfont-archer">&#xe606;</span>
                Hexo
            </span>
        
            <span class="sidebar-tag-name" data-tags="hexo-theme-archer">
                <span class="iconfont-archer">&#xe606;</span>
                hexo-theme-archer
            </span>
        
            <span class="sidebar-tag-name" data-tags="计算机网络">
                <span class="iconfont-archer">&#xe606;</span>
                计算机网络
            </span>
        
            <span class="sidebar-tag-name" data-tags="网络安全">
                <span class="iconfont-archer">&#xe606;</span>
                网络安全
            </span>
        
            <span class="sidebar-tag-name" data-tags="密码学">
                <span class="iconfont-archer">&#xe606;</span>
                密码学
            </span>
        
            <span class="sidebar-tag-name" data-tags="resume">
                <span class="iconfont-archer">&#xe606;</span>
                resume
            </span>
        
            <span class="sidebar-tag-name" data-tags="CSS">
                <span class="iconfont-archer">&#xe606;</span>
                CSS
            </span>
        
            <span class="sidebar-tag-name" data-tags="Github-actions">
                <span class="iconfont-archer">&#xe606;</span>
                Github-actions
            </span>
        
            <span class="sidebar-tag-name" data-tags="rxjs">
                <span class="iconfont-archer">&#xe606;</span>
                rxjs
            </span>
        
            <span class="sidebar-tag-name" data-tags="PostgreSQL">
                <span class="iconfont-archer">&#xe606;</span>
                PostgreSQL
            </span>
        
            <span class="sidebar-tag-name" data-tags="Windows">
                <span class="iconfont-archer">&#xe606;</span>
                Windows
            </span>
        
            <span class="sidebar-tag-name" data-tags="EditorConfig">
                <span class="iconfont-archer">&#xe606;</span>
                EditorConfig
            </span>
        
            <span class="sidebar-tag-name" data-tags="Prettier">
                <span class="iconfont-archer">&#xe606;</span>
                Prettier
            </span>
        
            <span class="sidebar-tag-name" data-tags="VSCode">
                <span class="iconfont-archer">&#xe606;</span>
                VSCode
            </span>
        
            <span class="sidebar-tag-name" data-tags="Linux">
                <span class="iconfont-archer">&#xe606;</span>
                Linux
            </span>
        
            <span class="sidebar-tag-name" data-tags="MySQL">
                <span class="iconfont-archer">&#xe606;</span>
                MySQL
            </span>
        
            <span class="sidebar-tag-name" data-tags="Github">
                <span class="iconfont-archer">&#xe606;</span>
                Github
            </span>
        
            <span class="sidebar-tag-name" data-tags="jsDiliver">
                <span class="iconfont-archer">&#xe606;</span>
                jsDiliver
            </span>
        
            <span class="sidebar-tag-name" data-tags="ES6">
                <span class="iconfont-archer">&#xe606;</span>
                ES6
            </span>
        
            <span class="sidebar-tag-name" data-tags="GCC">
                <span class="iconfont-archer">&#xe606;</span>
                GCC
            </span>
        
            <span class="sidebar-tag-name" data-tags="Docker">
                <span class="iconfont-archer">&#xe606;</span>
                Docker
            </span>
        
            <span class="sidebar-tag-name" data-tags="CPP">
                <span class="iconfont-archer">&#xe606;</span>
                CPP
            </span>
        
            <span class="sidebar-tag-name" data-tags="gRPC">
                <span class="iconfont-archer">&#xe606;</span>
                gRPC
            </span>
        
            <span class="sidebar-tag-name" data-tags="ESLint">
                <span class="iconfont-archer">&#xe606;</span>
                ESLint
            </span>
        
            <span class="sidebar-tag-name" data-tags="Protobuf">
                <span class="iconfont-archer">&#xe606;</span>
                Protobuf
            </span>
        
            <span class="sidebar-tag-name" data-tags="机器学习">
                <span class="iconfont-archer">&#xe606;</span>
                机器学习
            </span>
        
            <span class="sidebar-tag-name" data-tags="PyTorch">
                <span class="iconfont-archer">&#xe606;</span>
                PyTorch
            </span>
        
            <span class="sidebar-tag-name" data-tags="Telegram">
                <span class="iconfont-archer">&#xe606;</span>
                Telegram
            </span>
        
            <span class="sidebar-tag-name" data-tags="Bot">
                <span class="iconfont-archer">&#xe606;</span>
                Bot
            </span>
        
            <span class="sidebar-tag-name" data-tags="Koa">
                <span class="iconfont-archer">&#xe606;</span>
                Koa
            </span>
        
            <span class="sidebar-tag-name" data-tags="Sequelize">
                <span class="iconfont-archer">&#xe606;</span>
                Sequelize
            </span>
        
            <span class="sidebar-tag-name" data-tags="Travis">
                <span class="iconfont-archer">&#xe606;</span>
                Travis
            </span>
        
            <span class="sidebar-tag-name" data-tags="MTProto">
                <span class="iconfont-archer">&#xe606;</span>
                MTProto
            </span>
        
            <span class="sidebar-tag-name" data-tags="Nginx">
                <span class="iconfont-archer">&#xe606;</span>
                Nginx
            </span>
        
            <span class="sidebar-tag-name" data-tags="Markdown">
                <span class="iconfont-archer">&#xe606;</span>
                Markdown
            </span>
        
            <span class="sidebar-tag-name" data-tags="Webpack">
                <span class="iconfont-archer">&#xe606;</span>
                Webpack
            </span>
        
    </div>
    <div class="iconfont-archer sidebar-tags-empty">&#xe678;</div>
    <div class="tag-load-fail" style="display: none; color: #ccc; font-size: 0.6rem;">
        缺失模块，请参考主题文档进行安装配置：https://github.com/fi3ework/hexo-theme-archer#%E5%AE%89%E8%A3%85%E4%B8%BB%E9%A2%98
    </div> 
    <div class="sidebar-tags-list"></div>
</div>

        <div class="sidebar-panel-categories">
    <div class="sidebar-categories-name">
    
        <span class="sidebar-category-name" data-categories="学习琐事">
            <span class="iconfont-archer">&#xe60a;</span>
            学习琐事
        </span>
    
        <span class="sidebar-category-name" data-categories="前端开发">
            <span class="iconfont-archer">&#xe60a;</span>
            前端开发
        </span>
    
        <span class="sidebar-category-name" data-categories="后端开发">
            <span class="iconfont-archer">&#xe60a;</span>
            后端开发
        </span>
    
        <span class="sidebar-category-name" data-categories="技术琐事">
            <span class="iconfont-archer">&#xe60a;</span>
            技术琐事
        </span>
    
    </div>
    <div class="iconfont-archer sidebar-categories-empty">&#xe678;</div>
    <div class="sidebar-categories-list"></div>
</div>

    </div>
</div>

        <!-- site-meta -->
        <script>
    var siteMetaRoot = "/"
    if (siteMetaRoot === "undefined") {
        siteMetaRoot = '/'
    }
    var siteMeta = {
        url: "https://LolipopJ.github.io",
        root: siteMetaRoot,
        author: "Lolipop"
    }
</script>

        <!-- import experimental options here -->
        <!-- Custom Font -->

    <!-- Check browser compatibility of CSS variables -->
    <script>
        if (browserSupportCSSVariables === undefined) {
            var browserSupportCSSVariables = window.CSS && window.CSS.supports && window.CSS.supports('--a', 0);
        }
    </script>
    <script>
        if (browserSupportCSSVariables) {
            var customFontName = 'Noto Sans SC:n3,n4,n5,n7'
            var customFontUrl = 'https://fonts.googleapis.cnpmjs.org/css2?family=Noto+Sans+SC:wght@300;400;500;700&amp;display=swap'
            if (!customFontName) {
                console.log('Custom font name is not set or read failed');
            }
            if (!customFontUrl) {
                console.log('Custom font url is not set or read failed');
            }
        } else {
            console.error('Current browser doesn\'t support custom font.')
        }
    </script>
    <script src="/scripts/customFontLoader.js?v=20211217" defer></script>


        <!-- main func -->
        <script src="/scripts/main.js?v=20211217"></script>
        <!-- dark mode -->
        <script src="/scripts/dark.js?v=20211217"></script>
        <!-- fancybox -->
        <script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js" defer></script>
        <!-- algolia -->
        
            <div class="site-search site-search-loading">
    <div class="algolia-popup popup">
        <div class="algolia-search">
            <div class="algolia-search-input-icon">
                <i class="fa fa-search"></i>
            </div>
            <div class="algolia-search-input" id="algolia-search-input"></div>
            <div class="popup-btn-close">
                <i class="iconfont-archer">&#xe609;</i>
            </div>
        </div>

        <div class="algolia-results">
            <div id="algolia-stats" class="algolia-stats"></div>
            <div id="algolia-hits"></div>
            <div id="algolia-pagination" class="algolia-pagination"></div>
        </div>
    </div>
</div>

            <script src="/scripts/search.js?v=20211217" defer></script>
        
        <!-- busuanzi -->
        
            <script src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" async></script>
        
        <!-- CNZZ -->
        
        <!-- async load share.js -->
        
            <script src="/scripts/share.js?v=20211217" async></script>
        
        <!-- mermaid -->
        
    </body>
</html>
